<?php
/**
 * | 节程 [ 节程赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 *  | Copyright (c) 2020~2029 温州惊蛰网络科技有限公司 All rights reserved.
 * +----------------------------------------------------------------------
 *  | Licensed 节程并不是自由软件，未经许可不能去掉节程相关版权
 * +----------------------------------------------------------------------
 */


namespace app\index\service;

use app\index\model\AfterConfig;
use app\index\model\AfterOrderCommodity;
use app\index\model\Collage;
use app\index\model\Commodity;
use app\index\model\Configuration;
use app\index\model\Group;
use app\index\model\GroupCommodity;
use app\index\model\MembershipLevel;
use app\index\model\OrderCommodity;
use app\index\model\OrderCommodityAttach;
use app\index\model\OrderEvaluate;
use app\index\model\OrderMoneyChange;
use app\index\model\SeckillCommodity;
use app\index\model\SeckillCommoditySku;
use app\index\model\SkuInventory;
use app\index\model\Store;
use app\index\model\User;
use app\index\model\Distribution;
use app\index\util\CreateNo;
use app\index\util\Redis;
use app\index\model\Area;
use app\index\model\CarryModeNum;
use app\index\model\CarryModeWeight;
use app\index\model\FreightTemp;
use app\index\model\Order;
use app\index\model\OrderFreight;
use app\index\model\Sku;
use app\index\model\UserAddress;
use app\index\model\Coupon;
use app\index\model\UserCoupon;
use app\index\model\OrderAfter;
use app\index\model\PresellCommodity;
use app\shop_admin\model\AttachName;
use app\shop_admin\model\AttachValue;
use app\utils\Addons;
use think\App;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\exception\HttpException;
use think\exception\InvalidArgumentException;
use think\facade\Cache;
use think\facade\Db;
use app\utils\SendMsg;
use app\index\util\OrderCount;

class OrderService
{
    protected $redis;
    protected $user;
    private $hashKeys;
    private $mid;
    private $coupon;

    public function __construct()
    {
        global $user, $mid;
        $this->mid = $mid;
        $this->user = $user;
        $this->redis = Redis::getInstance();
    }

    public function createOrder(array $data, array $commoditys, string $type, array $coupon_arr, int $is_integral = 0, int $pid = 0)
    {
        global $token, $mid;
        $is_level = false;
        $user = User::find($this->user['id']);

        if (empty($user['status'])) throw new HttpException(HTTP_UNAUTH, "您已被拉黑，请联系管理员...");
        if (!empty($user['level']) && (empty($user['level_time']) || $user['level_time'] > date('Y-m-d'))) $is_level = $user['level'];

        if (!Cache::store('redis')->has("INDEX:" . $token . "-" . $mid)) throw new HttpException(HTTP_UNAUTH, "用户数据为空,请登录!");
        $arr = $this->typeOrder($commoditys, $type);
        $merchant_arr = [];
        foreach ($arr as $v) {
            $merchant_arr[$v['merchantId']][] = $v;//合并同一商户数据
        }
        $address = [];
        $code = "";
        if (array_key_exists('user_address_id', $data)) {
            $address = $this->getAddressCode($data['user_address_id']);
            $code = $address['code'];
            unset($address['code']);
        } else {
            $address['consignee'] = $data['consignee'];
            $address['iphone'] = $data['iphone'];
        }
        $up = [];
        $commodityList = [];
        $order_no_arr = [];
        $integral_commodity = [];
        try {
            foreach ($merchant_arr as $kk => $item) {
                $array = [];
                $attach = [];
                $data['money'] = 0;
                $y_money = 0;
                $data['user_id'] = $this->user['id'];
                $data['order_no'] = CreateNo::buildOrderNo($this->user['id']);
                $data['merchant_id'] = $kk;
                $order_no_arr[] = $data['order_no'];
                $coupon_data = [];
                foreach ($coupon_arr as $v1) {
                    if ($kk == $v1['merchant_id'])
                        $coupon_data[$data['order_no']] = $v1['coupon_id'];
                }

                $mark = 0;
                foreach ($item as $k => $v) {
                    $is_self = json_decode($this->redis->get(checkRedisKey("COMMODITY:" . $v['commodityId'])), true);
                    $is_self = !empty($is_self['is_self']) ? $is_self['is_self'] : 0;
                    $is_level = $is_level && $is_self == 1;
                    $array[$k]['commodity_id'] = intval($v['commodityId']);
                    $array[$k]['count'] = intval($v['num']);
                    $array[$k]['type'] = intval($v['type']);
                    $sku = array_key_exists('sku', $v) ? $v['sku'] : null;
                    $store = array_key_exists('store_id', $v) ? $v['store_id'] : null;
                    $array[$k]['sku_id'] = $sku;
                    if ($v['type'] == 2 && empty($store)) throw new HttpException(HTTP_NOTACCEPT, '自提订单门店不能为空!');
                    if ($v['type'] == 3 && empty($store)) throw new HttpException(HTTP_NOTACCEPT, '同城配送订单门店不能为空!');
                    $array[$k]['store_id'] = $store;
                    $commodity = empty($sku) ?
                        Commodity::where('id', $v['commodityId'])
                            ->field('
                            (total-sell) as count,is_limitation,limitation,inventory_type,limitation_time,name,limitation_type,retreat,
                            (case when is_original_price then original_price else sell_price end) as price
                            ')
                            ->find()
                            ->toArray() :
                        Commodity::with(['sku' => function ($query) use ($sku) {
                            $query->alias('a')
                                ->join('sku_inventory s', 'a.id = s.sku_id', 'LEFT')
                                ->where('s.sku_id', '=', $sku)
                                ->field('(s.total - s.sell) as count,a.commodity_id,s.sell_price');
                        }])
                            ->field('is_limitation,limitation,inventory_type,id,limitation_time,name,retreat,limitation_type')
                            ->find($v['commodityId'])
                            ->toArray();
                    $y_price = isset($commodity['price']) ? $commodity['price'] : $commodity['sku'][0]['sell_price'];
                    $y_money = bcadd($y_money, ($v['num'] * $y_price), 2);
                    if (!empty($v['attach']) && is_array($v['attach'])) $v['attach'] = implode(',', $v['attach']);
                    $integral_commodity[$kk][] = ["commodity" => intval($v['commodityId']), 'attach' => $v['attach'] ?? '', "num" => intval($v['num']), "price" => (new InventoryService($v['commodityId']))->getPrice($sku), "sku" => $sku, 'group' => $k];
                    if (in_array($commodity['inventory_type'], [0, 1])) {  //库存类型:1:下单前减库存,2:永不减库存,3:付款减库存
                        $inventory = new InventoryService($v['commodityId']);
                        $price = $inventory->subInventoryByCount($v['num'], $sku);
                        $commodityList[] = ["commodity" => intval($v['commodityId']), "num" => intval($v['num']), "price" => $price, "sku" => $sku];
                        // 预售减库存
                        if (isset($v['presell'])) {
                            PresellCommodity::decStock($v['presell']['id'], $v['num'], isset($v['sku']) ? $v['sku'] : null);
                        }
                    } else {
                        $count = empty($sku) ? $commodity['count'] : $commodity["sku"][0]['count'];
                        if ($count < $v['num']) throw new HttpException(HTTP_INVALID, '库存不足!');
                        //price
                        $price = array_key_exists('price', $commodity) ? $commodity['price'] : $commodity['sku'][0]['sell_price'];
                        $inventory = new InventoryService($v['commodityId']);
                        $redis_price = $inventory->getLevelPrice1($v['num'], $sku);
                        if (!empty($redis_price)) {
                            $price = $redis_price;
                        }
                    }
                    $sell_price = array_key_exists('price', $commodity) ? $commodity['price'] : $commodity['sku'][0]['sell_price'];
                    $discount_level_money[] = bcsub($sell_price * $v['num'], $price * $v['num'], 2);
                    if (!empty($commodity['is_limitation'])) {//限购
                        if ($commodity['limitation_type'] == 1 && $v['num'] > $commodity['limitation']) //单笔限购
                            throw new HttpException(HTTP_INVALID, "商品[" . $commodity['name'] . ']超出限购数量!');
                        if ($commodity['limitation_type'] == 2) {//历史限购
                            $orderCount = new OrderCount();
                            if ($orderCount->commodityByOrderCount($v['commodityId']) + $v['num'] > $commodity['limitation'])
                                throw new HttpException(HTTP_INVALID, "商品[" . $commodity['name'] . ']超出限购数量!');
                        }
                    }
                    $price = $price ?? 0;
                    $array[$k]['price'] = $price;
                    // 拼团
                    if (isset($v['group'])) {
                        $group = $v['group'];
                        $price = $group['leader_price'] != -1 ? $group['leader_price'] : $group['activity_price'];
                        $array[$k]['gc_id'] = $group['id'];
                        // 团员
                        if (isset($group['collage_id'])) {
                            $array[$k]['collage_id'] = $group['collage_id'];
                            $price = $group['activity_price'];
                        }
                        $address['order_from'] = 1;
                        $use_agent = $group['use_agent'];
                    }
                    // 秒杀
                    if (isset($v['seckill'])) {
                        $seckill = $v['seckill'];
                        $address['order_from'] = 2;
                        $array[$k]['sc_id'] = $seckill['id'];
                        $use_agent = $seckill['use_agent'];
                        $price = $seckill['activity_price'];
                        SeckillCommodity::decStock($seckill['id'], $v['num'], isset($v['sku']) ? $v['sku'] : null);
                    }
                    // 预售
                    if (isset($v['presell'])) {
                        $presell = $v['presell'];
                        $address['order_from'] = 3;
                        $array[$k]['pc_id'] = $presell['id'];
                        $use_agent = $presell['use_agent'];
                        $price = $presell['activity_price'];
                    }
                    $mark = $v['type'];
                    $array[$k]['retreat'] = $commodity['retreat'];
                    $array[$k]['money'] = bcmul($v['num'], $price, 2);
                    $array[$k]['mall_id'] = $this->mid;
                    $array[$k]['group'] = $k;
                    $data['money'] = bcadd($data['money'], ($v['num'] * $price), 2);
                    $data['order_type'] = intval($v['type']);
                    $data['discount_level_money'] = array_sum($discount_level_money);
                    // 附加属性
                    if (array_key_exists('attach', $v) && $v['attach']) {
                        $attachIds = is_array($v['attach']) ? $v['attach'] : explode(',', $v['attach']);
                        $attachValueStr = "";
                        foreach ($attachIds as $ak => $av) {
                            $attachValue = AttachValue::with("AttachName")->find($av);
                            // 库存判断
                            $sell = AttachValue::getSell($av);
                            if ($sell <= 0) {
                                throw new HttpException(HTTP_INVALID, "[" . $attachValue['name'] . ']库存不足!');
                            }
                            array_push($attach, [
                                'attach_id' => $attachValue['id'],
                                'attach_value' => $attachValue->AttachName->name . ':' . $attachValue['name'],
                                'commodity_id' => intval($v['commodityId']),
                                'mall_id' => $this->mid,
                                'merchant_id' => $kk,
                                'sku_id' => (isset($v['sku']) && $v['sku'] > 0) ? $v['sku'] : 0,
                                'group' => $k,
                                'num' => $v['num'],
                                'attach_price' => $attachValue['price']
                            ]);
                            $data['money'] += $attachValue['price'] * $v['num'];
                            $attachValueStr .= $attachValue->AttachName->name . ':' . $attachValue['name'] . ',';
                        }
                        $data['has_attach'] = 1;
                        $array[$k]['attach_value'] = rtrim($attachValueStr, ',');
                    }
                }
                // 添加同城配送运费
                if ($data['order_type'] == 3) {
                    $dst_Obj = new Distribution();
                    $s = Store::find($store);
                    $d = $dst_Obj->getFee($s, $data['user_address_id'], $y_money);
                    $w = 0;
                    foreach ($array as $akey => $avalue) {
                        $sku_id = $avalue['sku_id'];
                        $count = $avalue['count'];
                        if (!empty($sku_id)) {
                            $category = Sku::find($sku_id);
                            $w += $category['weight'] * $count;
                        } else {
                            $commodity = Commodity::find($avalue['commodity_id']);
                            $w += ((float)$commodity['weight']) * $count;
                        }
                    }
                    $wf = $dst_Obj->getWeightFee($store, $w);
                    $local = $d[0][0];
                    foreach ($local as $kl => $kv) {
                        if ($kv['error_code'] == 1) {
                            $data['money'] += $kv["distribution_fee"] + $wf;
                            $data['distribution_fee'] = $kv["distribution_fee"] + $wf;
                            break;
                        }
                    }
                }
                $data['money'] = round($data['money'], 2);
                unset($data['type']);
                $data['mall_id'] = $this->mid;
                $data['discount_amount'] = 0;
                $data['source'] = request()->header('usertype');
                $create = array_merge($data, $address);
                $res = Order::create($create);
                $res->orderCommodity()->saveAll($array);
                // 附加属性
                if (count($attach) > 0) {
                    $res->orderCommodityAttach()->saveAll($attach);
                }
                //计算积分
                $integral = new IntegralService();
                $integral->integral_address($array, $res->id, $this->user['id'], $this->mid);
                //打印小票

                $receipts = new ReceiptsService();
                $receipts->printer($res->id);

                //快递计算运费
                $res['freight'] = 0;
                if ($mark == 1) $res['freight'] = $this->reckonFreight($item, $res->id, $code, $data['user_address_id']);
                //优惠金额
                $res['coupon_money'] = 0;
                if (!empty($coupon_arr) && (new Addons())->check($this->mid, 3) && !empty($coupon_data)) {
                    $order_coupon = new OrderCouponService();
                    $res['coupon_money'] = $order_coupon->orderUserCoupon($coupon_data, $order_no_arr, [], 0);
                }
                //记录代理费
                if (!isset($use_agent) || $use_agent == 1) {
                    (new CommissionService)->getAgentMoney($res, $pid);
                }
                //订单自定义表单

                if (!empty($data['form_config'])){
                    $answers=json_decode($data['form_config'],true);
                    if (is_array($answers)){
                        $orderFormService= new OrderFormService();
                        $orderFormService->answer($res,$answers );
                    }
                }

                $up[] = $res;
            }

            $type == 2 ?
                $this->redis->del(checkRedisKey("TROLLEY:" . $this->user['id']))
                : array_map(function ($hashKeys) {
                $this->redis->hDel(checkRedisKey("TROLLEY:" . $this->user['id']), $hashKeys);
            }, $this->hashKeys);
            //---------------------------------------------积分抵扣------------------------------------------------------
            if (!empty($is_integral)) {
                $config = \app\index\model\Configuration::where('type', 'integralBalance')
                    ->where('mall_id', $this->mid)
                    ->find()
                    ->configuration;
                if ($config['is_open'] == 1) {
                    $deduction = $config['deduction'];
                    $deduction = $deduction * 100;
                    foreach ($up as $key => $value) {
                        $temp = $integral_commodity[$value['merchant_id']];
                        $discount = $integral->integral_calculation($temp, $this->user['id'], $data['money'], $deduction, $value->id, $this->mid);
                        if ($discount['money'] != 0) {
                            $integral->integral_deduction($discount, $this->user['id'], $deduction, $value->id, $this->mid);
                            $up[$key]->discount_amount = $discount['money'];
                        }
                    }
                }
            }

            //----------------------------------------------------------------------------------------------------------
        } catch (\think\Exception $e) {
            if (!empty($commodityList)) {
                foreach ($commodityList as $key => $val) {
                    $sku = array_key_exists('sku', $val) ? $val['sku'] : null;
                    $inventoryService = new InventoryService($val['commodity']);
                    $inventoryService->backInventoryToCache($val['num'], $val['price'], $sku);
                }
            }
            throw new Exception($e->getMessage(), HTTP_NOTACCEPT);
        }


        return [HTTP_SUCCESS, $up];
    }

    private function checkMemberPrice($user, $commodity, $price)
    {
        if (!Addons::check($user->mall_id, 20)) {
            return $price;
        }
        if (empty($user->level) || empty($commodity->is_open_member_price)) {
            return $price;
        }

        if ($commodity->member_price_type === 1) {
            $membershipLevel = MembershipLevel::where('level', '<=', $user->level)->order('level', 'desc')->find();
            $price = bcdiv((string)bcmul((string)$price, (string)$membershipLevel->discount), "10");
        } elseif ($commodity->member_price_type === 2) {
            $price = bcdiv((string)bcmul((string)$price, (string)$commodity->member_price), "10");
        } else {
            $price = $commodity->member_price;
        }

        return $price;
    }


    public function shopCartFreight(array $data, string $type, string $address_id = " ")
    {
        $arr = $this->typeOrder($data, $type);
        $code = " ";
        if (!empty(trim($address_id))) {
            $address = $this->getAddressCode($address_id);
            $code = $address['code'];
        }
        $store = [];
        foreach ($arr as $k => $v) {
            $store[$v['merchantId']][] = $v;
        }
        $shops = $this->uniquArr($store);
        $freight = [];
        foreach ($shops as $k => $v) {
            $money = $this->StoreFreight($v, $address_id, $code);
            $freight[] = ['merchantId' => $k, 'freight' => $money[0], 'type' => $money[1]];
        }
        return [HTTP_SUCCESS, $freight];
    }

    public function cityFreight($user_address_id, $commodity_id, $num, $sku)
    {
        $commodity = Commodity::find($commodity_id);
        if ($commodity['has_sku']) {
            $category = Sku::find($sku);
            $weight = $category['weight'] * $num;
            $commodity_price = SkuInventory::where('sku_id', $sku)->find()['sell_price'] * $num;
        } else {
            $weight = ((float)$commodity['weight']) * $num;
            $commodity_price = $commodity['sell_price'] * $num;
        }
        $store = Store::where('merchant_id', $commodity['merchant_id'])->select()->toArray();
        $distribution_data = [];
        $dst_Obj = new Distribution();
        foreach ($store as $key => $value) {
            // 门店配送费
            $dis = $dst_Obj->where('store_id', $value['id'])->find();
            if (!empty($dis)) {
                $fee = $dst_Obj->getFee($value, $user_address_id, $commodity_price);
                $distribution_data[$key]['distribution'] = $fee;
                // 续重收费
                $weight_fee = $dst_Obj->getWeightFee($value['id'], $weight);

                $distribution_data[$key]['weight_fee'] = $weight_fee;
            }

        }
        $data = [];

        foreach ($distribution_data as $k => $v) {
            $res = $this->checkDistribution($v);
            array_push($data, $res);
        }
        return [HTTP_SUCCESS, $data];
    }


    public function goodsCityFreight($user_address_id, $commoditys)
    {
        $information = [];
        foreach ($commoditys as $ckey => $cvalue) {
            $weight = 0; // 总重量
            $commodity_price = 0; // 商品总价格
            foreach ($cvalue[1] as $gkey => $gvalue) {
                $commodity = Commodity::find($gvalue['id']);
                if ($commodity['has_sku']) {
                    $category = Sku::find($gvalue['sku']);
                    $weight += $category['weight'] * $gvalue['num'];
                    $commodity_price += SkuInventory::where('sku_id', $gvalue['sku'])->find()['sell_price'] * $gvalue['num'];
                } else {
                    $commodity_price += $commodity['sell_price'] * $gvalue['num'];
                    $weight += $commodity['weight'] * $gvalue['num'];
                }
            }
            $store = Store::where('mall_id', $this->mid)->where('merchant_id', $cvalue[0]['merchant_id'])->select()->toArray();
            $distribution_data = [];
            $dst_Obj = new Distribution();
            foreach ($store as $key => $value) {

                $dis = $dst_Obj->where('store_id', $value['id'])->find();
                if (!empty($dis)) {
                    // 门店配送费
                    $fee = $dst_Obj->getFee($value, $user_address_id, $commodity_price);

                    $distribution_data[$key]['distribution'] = $fee;

                    // 续重收费
                    $weight_fee = $dst_Obj->getWeightFee($value['id'], $weight);
                    $distribution_data[$key]['weight_fee'] = $weight_fee;
                }
            }
            $data = [];

            foreach ($distribution_data as $k => $v) {
                $res = $this->checkDistribution($v);
                array_push($data, $res);
            }
            array_push($information, [$cvalue[0]['merchant_id'], $data]);
        }

        return [HTTP_SUCCESS, $information];
    }

    private function checkDistribution($v)
    {
        // 门店
        $res[0] = $v['distribution'][0]['store'];
        // 门店区域
        $local = $v['distribution'][0][0];
        $dd = "未设置";
        $remark = -2;
        foreach ($local as $lkey => $lvalue) {
            if ($lvalue['error_code'] == 1) {
                $dd = $lvalue['distribution_fee'] + $v['weight_fee'];
                break;
            }
            if ($lvalue['error_code'] > $remark) {
                $remark = $lvalue['error_code'];
                $dd = $lvalue['error_msg'];
            }
            unset($lvalue);
        }
        $res[1] = $dd;

        return $res;
    }


    private function uniquArr($arr)
    {
        $res = array();
        foreach ($arr as $k => $v) {
            foreach ($v as $key => $value) {
                if (isset($res[$k][$value['commodityId']])) {
                    $res[$k][$value['commodityId']]['num'] += $value['num'];
                    unset($value[$key]);
                } else {
                    $res[$k][$value['commodityId']] = $value;
                }
            }
        }
        return $res;
    }


    public function StoreFreight(array $data, int $address_id, string $address_code = " ")
    {
        count($data) == count($data, 1) ? $res[] = $data : $res = $data;
        $arr = [];
        foreach ($res as $k => $v) {
            $merge = Db::name('commodity')
                ->alias('a')
                ->where('a.id', '=', $v['commodityId'])
                ->where('mall_id', $this->mid)
                ->field('a.merchant_id,a.ft_type,a.ft_id,a.ft_price,a.id,a.has_sku')
                ->find();
            $arr[$k] = array_merge($v, $merge);
        }
        $freight_money = 0;
        foreach ($arr as $v) {
            $no_carry = FreightTemp::where('id', $v['ft_id'])->value('no_carry');
            $arr1 = explode(',', $no_carry);
            $type = 1;
            $res = $v['commodityId'];
            if (!in_array($address_code, $arr1)) {
                if ($v['type'] == 2) {
                    // 购物车提交
                    $m = 0;
                } else {
                    // 单页面提交
                    $m = $this->compute($v, $v['num'], $address_code);
                }
                $freight_money = bcadd($freight_money, $m, 2);
            } else {
                // 地址不在不可配送区域
                $freight_money = 0;
                $type = 2;
                break;
            }
            // Cache::store('redis')->set('FREIGHT:' . $v['merchantId'] . "-" . $address_id . "-" . $v['commodityId'] . "-" . $v['num'], $freight_money);
        }
        return [$freight_money, $type, $res];
    }

    public function setDefaultAddress(int $id)
    {
        UserAddress::where('user_id', $this->user['id'])->where('mall_id', $this->mid)->update(['type' => 1]);
        $res = UserAddress::update(['type' => 2], ['id' => $id]);
        return [HTTP_SUCCESS, $res];
    }

    /**
     * @param array $commoditys
     * @param string $type 1直接购买，2部分购物车， 3全部购物车, 4拼团
     * @return array
     */
    private function typeOrder(array $commoditys, string $type)
    {
        $arr = [];
        $this->hashKeys = [];
        if ($type == 1) {
            $arr[] = $commoditys;
        } elseif ($type == 2) {
            $list = array_values($this->redis->hGetAll(checkRedisKey("TROLLEY:" . $this->user['id'])));
            $arr = array_map(function ($item) {
                return json_decode($item, true);
            }, $list);

            //删除购物车限购添加
            $keys = $this->redis->keys("LIMITATIONCOMMODITY_" . $this->user['id'] . "_*");
            $this->redis->del($keys);
        } elseif ($type == 3) {
            foreach ($commoditys as $v) {
                $hashKey = self::getHashKey($v);
                $this->hashKeys[] = $hashKey;

                $commodityData = json_decode($this->redis->hGet(checkRedisKey("TROLLEY:" . $this->user['id']), $hashKey), true);
                $arr[] = $commodityData;

                //减少购物车限购添加
                $commodityLimitation = $this->redis->get("LIMITATIONCOMMODITY_" . $this->user['id'] . "_" . $commodityData['commodityId']);
                if (!empty($commodityLimitation)) {

                    $limitation = bcsub((string)$commodityLimitation, (string)$commodityData['num']);
                    $this->redis->set("LIMITATIONCOMMODITY_" . $this->user['id'] . "_" . $commodityData['commodityId'], $limitation);
                }

            }
        } elseif ($type == 4) {
            $sku = isset($commoditys['sku']) ? $commoditys['sku'] : null;
            $collage_id = isset($commoditys['collage_id']) ? $commoditys['collage_id'] : 0;
            $group_level = isset($commoditys['group_level']) ? $commoditys['group_level'] : 0;
            $commoditys['group'] = GroupCommodity::check($commoditys['commodityId'], $sku, $this->user, $collage_id, $group_level, $commoditys['num']);
            $arr[] = $commoditys;
        } else if ($type == 5) {
            $sku = isset($commoditys['sku']) ? $commoditys['sku'] : null;
            $commoditys['seckill'] = SeckillCommodity::check($commoditys['commodityId'], $sku, $this->user, $commoditys['num']);
            $arr[] = $commoditys;
        } else if ($type == 6) {
            $sku = isset($commoditys['sku']) ? $commoditys['sku'] : null;
            $commoditys['presell'] = PresellCommodity::check($commoditys['commodityId'], $sku, $this->user, $commoditys['num']);
            $arr[] = $commoditys;
        }
        if (empty(array_filter($arr))) throw new HttpException(HTTP_INVALID, "购物车商品数据为空");
        if (in_array($type, [2, 3])) {
            foreach ($commoditys as $v) {
                foreach ($arr as $kk => $vv) {
                    $sku = array_key_exists('sku', $vv) ? $vv['sku'] : null;
                    $commoditys_sku = array_key_exists('sku', $v) ? $v['sku'] : null;
                    $store_id = array_key_exists('store_id', $v) ? $v['store_id'] : null;
                    if ($v['id'] == $vv["commodityId"] && $commoditys_sku == $sku) {
                        $arr[$kk]['type'] = $v['type'];
                        $arr[$kk]['store_id'] = ($v['type'] == 2 || $v['type'] == 3) ? $store_id : null;
                        //测试
                    }
                }
            }
        }
        //测试 防止提交数据和redis不一致导致报错
        foreach ($arr as $k => $v) {
            if (!array_key_exists('type', $v) || empty($v)) unset($arr[$k]);

            if (!empty($v['attach'])) {
                $attachs = is_array($v['attach']) ? $v['attach'] : explode(',', $v['attach']);
                $values = AttachValue::alias('v')
                    ->field("v.name as vname, n.name as name, need, toplimit, count(*) as count")
                    ->join('attach_name n', 'v.attach_name_id = n.id', 'left')
                    ->where('v.id', 'in', $attachs)
                    ->group('v.attach_name_id')
                    ->select()->toArray();
                foreach ($values as $va => $vk) {
                    if ($vk['count'] > $vk['toplimit']) {
                        throw new HttpException(HTTP_INVALID, $vk['name'] . ':' . $vk['vname'] . "选择超过".$vk['toplimit']."上限！");
                    }
                    if ($vk['count'] < $vk['need']) {
                        throw new HttpException(HTTP_INVALID, $vk['name'] . ':' . $vk['vname'] . "请至少选满".$vk['need']."个！");
                    }
                }
                foreach ($attachs as $ka => $kv) {
                    $scok = AttachValue::getSell($kv, true);
                    $name = AttachName::find($scok[1]['attach_name_id']);
                    if ($v['num'] > $scok[0]) {
                        throw new HttpException(HTTP_INVALID, $name['name'] . ':' . $scok[1]['name'] . "库存不足！");
                    }
                }
            }
        }
        return $arr;
    }


    private function getAddressCode(string $user_address_id)
    {
        $address = UserAddress::where('id', $user_address_id)->where('mall_id', $this->mid)->field('address,consignee,iphone')->find()->toArray();
        $address_arr = explode(',', $address['address']);
        // $address_code = Area::where('name', $address_arr[0])->value('area_code');
        $address_code = Area::where('name', $address_arr[2])->value('area_code');
        $address['code'] = $address_code;
        return $address;
    }

    private function reckonFreight(array $data, int $oid, string $address_code, int $user_address_id)
    {
        try {
            foreach ($data as $k => $v) {
                $merge = Db::name('commodity')
                    ->alias('a')
                    ->where('a.id', '=', $v['commodityId'])
                    ->where('mall_id', $this->mid)
                    ->field('merchant_id,ft_type,ft_id,ft_price,id,has_sku')
                    ->find();
                $data[$k] = array_merge($v, $merge);
            }
            $save = [];
            $ids = '';
            $freight_money = 0;
            $store[] = $data;
            $arr = $this->uniquArr($store);
            foreach ($arr[0] as $v) {
                $sku = array_key_exists('sku', $v) ? $v['sku'] : null;
                $ids .= $v['id'] . "-" . $sku . ',';
                $mid = $v['merchantId'];
                $key = 'FREIGHT:' . $v['merchantId'] . "-" . $user_address_id . "-" . $v['commodityId'] . "-" . $v['num'];
                if (Cache::store('redis')->has(checkRedisKey($key))) {
                    $m = Cache::pull(checkRedisKey($key))[0];
                } else {
                    $no_carry = FreightTemp::where('id', $v['ft_id'])->where('mall_id', $this->mid)->value('no_carry');
                    $arr = explode(',', $no_carry);
                    if (!in_array($address_code, $arr)) {
                        $m = $this->compute($v, $v['num'], $address_code);
                    } else {
                        // $m = 0;
                        throw new Exception("该区域不接受配送，请换个地址试试吧", HTTP_NOTACCEPT);
                        //$m = 0;
                    }
                }
                $freight_money = bcadd($freight_money, $m, 2);
                $save = ['order_id' => $oid, 'merchant_id' => $mid, 'mall_id' => $this->mid, 'freight' => $freight_money, 'cids' => rtrim($ids, ',')];
            }
            (new OrderFreight())->save($save);
            return $freight_money;
        } catch (DataNotFoundException $e) {
            throw new DataNotFoundException($e->getMessage());
        } catch (ModelNotFoundException $e) {
            throw new ModelNotFoundException($e->getMessage());
        } catch (DbException $e) {
            throw new DbException($e->getMessage());
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
    }


    private function compute(array $arr, string $count, string $code)
    {
        $freight = FreightTemp::find($arr['ft_id']);
        //0:包邮,1:配送模板,2:统一价格
        if ($arr['ft_type'] == 0) {
            return 0;
        } elseif ($arr['ft_type'] == 1) {
            if (Cache::store('redis')->has(checkRedisKey('FT:' . $arr['ft_id'] . '-' . $code))) {
                $weight = json_decode(Cache::store('redis')->get(checkRedisKey('FT:' . $arr['ft_id'] . '-' . $code)));
            } else {
                //配送区域内
                $weight = empty($freight['carry_mode_type']) ?
                    Db::query("select * from jiecheng_carry_mode_num where ft_id= " . $arr['ft_id'] . " and  district is not null and  mall_id=" . $this->mid . " and find_in_set(" . $code . ",district) limit 1 ") :
                    Db::query("select * from jiecheng_carry_mode_weight where ft_id= " . $arr['ft_id'] . " and  district is not null and  mall_id=" . $this->mid . " and find_in_set(" . $code . ",district) limit 1");

                //配送区域外
                if (empty($weight)) {
                    $weight = empty($freight['carry_mode_type']) ?
                        CarryModeNum::where('ft_id', $arr['ft_id'])->where('mall_id', $this->mid)->where("district_value", "全国统一运费")->find()->toArray() :
                        CarryModeWeight::where('ft_id', $arr['ft_id'])->where('mall_id', $this->mid)->where("district_value", "全国统一运费")->find()->toArray();
                }
                Cache::store('redis')->tag('FT')->set(checkRedisKey("FT:" . $arr['ft_id'] . '-' . $code), json_encode($weight), 60 * 60 * 24 * 30);
            }
            $sku = array_key_exists('sku', $arr) ? $arr['sku'] : null;
            $tally = $freight['carry_mode_type'] == 0 ? $count : (Sku::where('id', $sku)->value('weight') * $count);
            return $this->price($tally, $weight, $freight['carry_mode_type']);
        } elseif ($arr['ft_type'] == 2) {
            return $arr['ft_price'];
        }
    }


    private function price($count, $fts, $type)
    {

        $fts = (array)$fts;
        foreach ($fts as $v) {
            if (is_object($v))
                $fts = (array)($v);
            else
                break;
        }
        if ($type) {
            $second_weight = $fts['second_weight'] == 0 ? 1 : $fts['second_weight'];
            if ($count - $fts['first_weight'] <= 0) {
                return $fts['first_amount'];
            } elseif ($count - $fts['first_weight'] > 0) {
                $res = bcmul(ceil(($count - $fts['first_weight']) / $second_weight), $fts['second_amount'], 2); //bc
                return bcadd($res, $fts['first_amount'], 2);
            }
        } else {
            $second_piece = $fts['second_piece'] == 0 ? 1 : $fts['second_piece'];
            if ($count - $fts['first_piece'] <= 0) {
                return $fts['first_amount'];
            } elseif ($count - $fts['first_piece'] > 0) {
                $res = bcmul(ceil(($count - $fts['first_piece']) / $second_piece), $fts['second_amount'], 2); //bc
                return bcadd($res, $fts['first_amount'], 2);
            }
        }

    }


    public function userAddressList(string $page, string $size)
    {
        $res = UserAddress::where('user_id', $this->user['id'])
            ->where('mall_id', $this->mid)
            ->field('id,address,consignee,iphone,create_time,type')
            ->paginate(['page' => $page, 'list_rows' => $size]);
        return [HTTP_SUCCESS, $res];
    }


    public function addUserAddress(array $data)
    {
        $data['user_id'] = $this->user['id'];
        if (array_key_exists('type', $data) && $data['type'] = 2) {
            UserAddress::where('user_id', $this->user['id'])->where('mall_id', $this->mid)->update(['type' => 1]);
        }
        $data['mall_id'] = $this->mid;
        $res = UserAddress::create($data);
        return [HTTP_SUCCESS, $res];
    }

    public function delUserAddress($id)
    {
        $del = UserAddress::destroy($id);
        return [HTTP_SUCCESS, $del];
    }


    public function saveUserAddress(array $data)
    {
        $id = $data['id'];
        unset($data['id']);
        $data['mall_mid'] = $this->mid;
        $up = UserAddress::update($data, ['id' => $id]);
        return [HTTP_SUCCESS, $up];
    }


    public function orderList(array $data, int $page = 1, int $size = 10)
    {
        $res = \app\index\model\view\OrderListView::where($this->bulidWhere($data))
            ->with(['orderCommodity'])
            ->order('create_time DESC')
            ->paginate(['page' => $page, 'list_rows' => $size]);

        foreach ($res as $k => $v) {
            if ($v['has_attach'] == 1) {
                $ee = Db::name("order_commodity_attach")->where('order_id', $v['id'])->select();
                $res[$k]['attach'] = $ee;
            }
            foreach ($v['orderCommodity'] as $ok => $ov) {
                $collage = Collage::find($ov['collage_id']);
                $res[$k]['orderCommodity'][$ok]['group_status'] = empty($collage) ? 0 : $collage['status'];
                // 拼团
                $group = explode(",", $ov['gc_id']);
                if (!empty($group[0])) {
                    $gc = GroupCommodity::find($group[0]);
                    if (isset($group[1])) {
                        $success_num = json_decode($gc['success_num'], true);
                        $res[$k]['orderCommodity'][$ok]['group'] = $success_num[$group[1]];
                    } else {
                        $res[$k]['orderCommodity'][$ok]['group'] = $gc['success_num'];
                    }
                }
            }
        }

        return [HTTP_SUCCESS, $res];
    }

    public function orderRefund(int $page = 1, $size = 10)
    {
        $res = Order::with(["order_commodity"])
            ->where('user_id', $this->user['id'])
            ->where('after_status', '<>', "3")
            ->order('create_time DESC')
            ->paginate(['page' => $page, 'list_rows' => $size]);
        foreach ($res as $key => $value) {
            foreach ($value['order_commodity'] as $okey => $ovalue) {
                $ocom = $res[$key]['order_commodity'][$okey];
                $commodity = Commodity::find($ovalue['commodity_id']);
                $ocom['after'] = AfterOrderCommodity::with(['info'])->where('ocid', $ovalue['id'])->select();
                $ocom['commodity'] = $commodity;
                $attch = Db::name("order_commodity_attach")
                    ->where('order_id', $ovalue['order_id'])
                    ->where('group', $ovalue['group'])
                    ->select();
                if (count($attch) > 0) {
                    $ocom['attach'] = $attch;
                }
                if (!empty($ocom['sku_id'])) {
                    $ocom['sku'] = Sku::find($ovalue['sku_id']);
                }
            }
        }
        return [HTTP_SUCCESS, $res];
    }

    public function orderInfo(int $id)
    {

        $config = Configuration::where('type', 'rightsSetting')->field('configuration')->find()->toArray();
        if (empty($config)) throw new Exception("交易设置未配置，请到后台（订单-交易设置）配置相关参数", HTTP_UNAUTH);
        $config = $config['configuration'];
        $res = Order::with([
            'order_commodity' => function ($sql) use ($id) {
                $orderCommodityWith = [
                    'commodity' => function ($query) {
                        $query->field('id,name,master,type,classify_value,has_sku');
                    },
                    'sku' => function ($query) {
                        $query->field('id,pvs_value');
                    },
                    'store' => function ($query) {
                        $query->field('id,name,district,address,address,longitude,latitude');
                    },
                    'after_commodity' => function ($query) {
                        $query->field('ocid,order_after_id')
                            ->order('order_after_id DESC')
                            ->with(['info' => function ($sql) {
                                $sql->bind(['id', 'state']);
                            }]);
                    }
                ];
            if (checkAddons(23)) {
                $orderCommodityWith = [
                    'commodity' => function ($query) {
                        $query->field('id,name,master,type,classify_value,has_sku');
                    },
                    'sku' => function ($query) {
                        $query->field('id,pvs_value');
                    },
                    'store' => function ($query) {
                        $query->field('id,name,district,address,address,longitude,latitude');
                    },
                    'after_commodity' => function ($query) {
                        $query->field('ocid,order_after_id')
                            ->order('order_after_id DESC')
                            ->with(['info' => function ($sql) {
                                $sql->bind(['id', 'state']);
                            }]);
                    },
                    'form' => function ($query) use ($id) {
                            $query->where(['order_id' => $id]);
                    }
                ];
            }
                $sql->field('id,order_id,attach_value,count,money,commodity_id,status,sku_id,store_id,retreat,after_type,after_status,discount_amount,is_evaluate,logistics_no,express_company,price,money AS pay_money,group,type,gc_id,collage_id,collage_item_id')
                    ->with($orderCommodityWith);
            },
            'freight' => function ($sql) {
                $sql->bind(['freight']);
            },
            'invoice',
            'after',
            checkAddons(23) ? 'form' : 'after'
        ])
            ->field('id,order_no,has_attach,pay_no,status,remake,is_evaluate,money,address,pay_id,consignee,iphone,after_status,after_type,order_type,discount,discount_amount,create_time,distribution_fee,money AS pay_money,order_from')
            ->find($id);

        if (empty($res)) throw new Exception('无权查看', HTTP_UNAUTH);
        $res = $res->toArray();
        $res['is_open'] = 0;
        if ($config['is_rights_apply'] == 1 && !in_array($res['status'], [1, 6, 4, 11, 12]) && !in_array($res['after_status'], [1, 2])) $res['is_open'] = 1;
        if ($res['has_attach'] == 1) {
            $res['attach'] = Db::name("order_commodity_attach")->where('order_id', $id)->select()->toArray();
            foreach ($res['attach'] AS $key => $value) {
                $res['pay_money'] += $value['attach_price'];
                $attach[$value['commodity_id']][$value['group']][$value['sku_id']][] = $value['attach_price'];
            }
        }
        $t = $res['order_commodity'];
        $res['pay_money'] = getOrderPayMoney($res['pay_money'], $res['discount_amount'], $res['discount']);
        //确定是否可退款以及退款金额计算
        $scale=$this->changeOrderPrice($res['id']);

        foreach ($t as $key => $value) {
            $t[$key]['is_open'] = 0;
            if ($config['is_rights_apply'] == 1 && $config['refund_single'] = 1) $t[$key]['is_open'] = 1;
            if (!empty($value['after_commodity'])) $t[$key]['is_open'] = 0;
            if (in_array($value['after_status'], [1, 4])) $res['is_open'] = 0;
            if (in_array($value['status'], [1, 6, 11, 4])) $t[$key]['is_open'] = 0;
            if (!empty($attach[$value['commodity_id']][$value['group']])) {
                $a = $attach[$value['commodity_id']][$value['group']];
                if (!empty($value['sku_id']) && !empty($a[$value['sku_id']]))
                    $t[$key]['pay_money'] += (array_sum($a[$value['sku_id']]) * $value['count']);

                else
                    $t[$key]['pay_money'] += (array_sum($a[0]) * $value['count']);
            }
            $t[$key]['pay_money']=number_format($t[$key]['pay_money']*$scale,2);
            // 拼团
            $group = explode(",", $value['gc_id']);
            if (!empty($group[0])) {
                $gc = GroupCommodity::find($group[0]);
                if (isset($group[1])) {
                    $success_num = json_decode($gc['success_num'], true);
                    $t[$key]['collage'] = $success_num[$group[1]];
                } else {
                    $t[$key]['collage'] = $gc['success_num'];
                }
            }
        }

        getOrderCommdityPayMoney($res['discount'], $t);
        $res['order_commodity'] = $t;
        $res['return_money'] = 0;
        foreach ($res['after'] as $v)
            if (in_array($v['type'], [1, 2]) && in_array($v['state'], [5, 7, 8])) $res['return_money'] += $v['money'];
        $res['refund_explain'] = $config['refund_explain'];
        #运费为空时设为0
        $res['freight'] = empty($res['freight']) ? 0 : $res['freight'];


//        $res['pay_money']=$res['money'];

        return [HTTP_SUCCESS, $res];
    }
    #计算出最终减价或上调比例
    public function changeOrderPrice($order_id){

        $old_model= OrderMoneyChange::where(['order_id'=>$order_id])->order('id asc')->find();

        if ($old_model){
            $new_model= OrderMoneyChange::where(['order_id'=>$order_id])->order('id desc')->find();
            $money= $old_model->old_money-$new_model->new_money;
            $a=($old_model->old_money - $money) / $old_model->old_money;
            $b=(float)sprintf("%.6f",(float)$a);
            return $b;
        }
        return 1 ;
    }

    public function orderDel(int $id)
    {
        $data = [
            'status' => 12,
            'settlement' => 3
        ];
        $find = Order::find($id);
        if ($find['status'] != 1) throw new HttpException(HTTP_INVALID, "该订单不是待支付的状态无法取消");
        if ($find['discount'] > 0) $this->return_coupon($id);
        Order::update($data, ['id' => $id]);

        $orders = OrderCommodity::where('a.order_id', $id)
            ->alias('a')
            ->where('a.mall_id', $this->mid)
            ->join('commodity c', 'a.commodity_id = c.id', 'LEFT')
            ->join('sku_inventory s', 'a.sku_id = s.sku_id', 'LEFT')
            ->field('a.commodity_id,a.count,(CASE WHEN c.has_sku = 1 THEN s.sell_price ELSE c.sell_price END) as price ,a.sku_id,c.inventory_type,a.status,a.sc_id,a.pc_id')
            ->select();
        // 分销
        Db::name('agent_bill_temporary')
            ->where('order_id', $id)
            ->delete();
        Db::name('order_agent_profit')
            ->where('order_id', $id)
            ->delete();

        OrderCommodity::where('order_id', $id)->where('mall_id', $this->mid)->update(['status' => 11]);

        foreach ($orders as $v) {
            // 秒杀
            if ($find['order_from'] == 2) {
                SeckillCommodity::incStock($v['sc_id'], $v['count'], $v['sku_id']);
            }
            $c = Commodity::find($v['commodity_id']);
            if (!empty($c)) {
                if (in_array($v['inventory_type'], [1, 2]) || (in_array($v['inventory_type'], [3]) && in_array($v['status'], [2, 3, 7]))) {
                    $inventory = new InventoryService($v['commodity_id']);
                    $inventory->backInventory($v['count'], $v['price'], $v['sku_id']);
                    // 预售
                    if ($find['order_from'] == 3) {
                        PresellCommodity::incStock($v['pc_id'], $v['count'], $v['sku_id']);
                    }
                }
            }
        }
        return [HTTP_CREATED, "成功!"];
    }

    public function confirm(int $id, array $data = [])
    {
        $find = Order::find($id);
        // after_status 维权状态: 1- 维权中 2-维权完成 3-未维权 4-维权驳回 after_type 1-整单维权 2-单品维权
        foreach ($data as $v) {
            $find1 = OrderCommodity::find($v);
            if (in_array($find1['after_status'], [2])) continue;
            if (in_array($find1['after_status'], [1])) throw new Exception('维权中无法确定收货', HTTP_INVALID);
            OrderCommodity::where(['id' => $v])->where('mall_id', $this->mid)->update(['status' => 7, 'receiving_time' => date('Y-m-d H:i:s', time())]);
        }

        $this->upOrderState($id);
        //开始计算佣金
//        $commission = new CommissionService();
//        $commission->settlement($find);
        //打印小票
        $receipts = new ReceiptsService();
        $receipts->printer($id, 'receiving');
        // 发送消息
        $sendMsg = new SendMsg("订单收货通知");
        $msgData = [
            'user_name' => $find['consignee'],
            'order_no' => $find['order_no'],
            'order_cash' => $find['money'],
            'order_create_time' => $find['create_time']
        ];
        $sendMsg->send($this->user, $msgData, '');
        return [HTTP_SUCCESS, "成功!"];
    }

    public function evaluate(int $oid, array $evaluate, int $source)
    {

        $conifg = Configuration::where('type', 'tradeSetting')->where('mall_id', $this->mid)->value('configuration');
        $js = json_decode($conifg, true);
        if ($js['order_evaluate'] = 0) throw new HttpException(HTTP_UNPROCES, "评价功能未开启");
        $arr = [];
        count($evaluate) == count($evaluate, 1) ? $list[] = $evaluate : $list = $evaluate;
        $find = OrderEvaluate::where('order_id', $oid)->where('mall_id', $this->mid)->find();
        if ($find) throw new HttpException(HTTP_UNPROCES, "不能重复评价");
        $config = Configuration::where('type', 'tradeSetting')->where('mall_id', $this->mid)->value('configuration');
        $js = json_decode($config, true);
        $state = empty($js['audit_evaluate']) ? 2 : 1;
        foreach ($list as $v) {
            $sku = OrderCommodity::find($v['ocid']);
            $arr[] = [
                'commodity_id' => $v['commodity_id'],
                'user_id' => $this->user['id'],
                'mall_id' => $this->mid,
                'order_id' => $oid,
                'img_url' => json_encode($v['img_urls']),
                'content' => $this->filter($v['content']),
                'score' => $v['score'],
                'sku' => $sku['sku_id'],
                'source' => $source,
                'state' => $state
            ];
            OrderCommodity::where(['id' => $v['ocid']])->where('mall_id', $this->mid)->update(['is_evaluate' => 1]);
        }
        Order::update(['is_evaluate' => 1], ['id' => $oid]);
        $res = (new OrderEvaluate())->saveAll($arr);
        return [HTTP_SUCCESS, $res];
    }


    public function logistics(string $code)
    {

//        $res = express($code);
//        dd($res);
        if (Cache::store('redis')->has(checkRedisKey('LOGISTICS:' . $code))) {
            $res = json_decode(Cache::store('redis')->get(checkRedisKey('LOGISTICS:' . $code)), true);
        } else {
            try {
                $res = express($code);
            } catch (\Exception $e) {
                return [HTTP_NOTACCEPT, $e->getMessage()];
            }
        }
        return [HTTP_SUCCESS, $res];
    }

    private function bulidWhere(array $data)
    {
        $where = [];
        $res = [];
        $where[] = ['user_id', '=', $this->user['id']];
        $where[] = ['mall_id', '=', $this->mid];
        if (!empty($data['order_type']))
            $where[] = ['order_type', '=', $data['order_type']];
        else if (!empty($data['state']) && $data['state'] == 1)
            $where[] = ['order_type', 'IN', [1, 2, 3]];
        else if (!empty($data['state']) && $data['state'] != 4)
            $where[] = ['order_type', 'IN', [1, 3]];
        if (array_key_exists('state', $data) && $data['state'] == 8) $where[] = ['is_evaluate', '=', 0];
        if (!empty($data['state'])) $res[] = $this->setOrderState($data['state'], $data['order_type'] ?? 0);
        return array_merge($where, $res);
    }

    private function getHashKey(array $data)
    {
        $str = "";
        foreach ($data as $k => $v) {
            if (!empty($v) && in_array($k, ['sku', 'id', 'attach'])) {
                if ($k == "attach") {
                    $v = implode(',', $data['attach']);
                }
                $str .= $k . ":" . $v . '-';
            }
        }
        return rtrim($str, '-');
    }


    private function filter(string $string)
    {
        $path = $_SERVER['DOCUMENT_ROOT'] . "/mgc.txt";
        $str = file_get_contents($path);
        $str_arr = explode("|", $str);
        $str_arr1 = array_combine($str_arr, array_fill(0, count($str_arr), "**"));
        return strtr($string, $str_arr1);
    }


    private function matchCoupon($userCouponList, $commodityList, $moneyTotal)
    {
        $unavailable = [];
        $available = [];
        foreach ($userCouponList as $k => $v) {
            if ($v->coupon->conditions > $moneyTotal) {
                $unavailable[] = $v;
                continue;
            }
            if ($v->coupon->time_limit_type == 0 &&
                time() > strtotime($v->coupon->create_time . "+" . $v->coupon->limit_time . "day")) {
                $unavailable[] = $v;
                continue;
            } elseif ($v->coupon->time_limit_type == 1 &&
                (time() > strtotime($v->coupon->limit_indate_end) || time() < strtotime($v->coupon->limit_indate_begin))) {
                $unavailable[] = $v;
                continue;
            }

            if ($v->coupon->commodity_limit_type == 1) {
                $allowList = explode(",", $v->coupon->commodity_limit);
                $diffCommodity = array_intersect_key($commodityList, array_flip(array_diff(array_keys($commodityList), $allowList)));
                $diffMoney = 0;
                foreach ($diffCommodity as $i => $j) {
                    bcadd((string)$diffMoney, bcmul((string)$j['count'], (string)$j['discount']));
                }
                $money = bcsub((string)$moneyTotal, (string)$diffMoney);
                if ($money < $v->coupon->conditions) {
                    $unavailable[] = $v;
                    continue;
                }
            } elseif ($v->coupon->commodity_limit_type == 2) {
                $allowList = explode(",", $v->coupon->commodity_limit);

                $diffCommodity = array_intersect_key($commodityList, array_flip(array_intersect(array_keys($commodityList), $allowList)));
                $diffMoney = 0;
                foreach ($diffCommodity as $i => $j) {
                    bcadd((string)$diffMoney, bcmul((string)$j['count'], (string)$j['discount']));
                }
                $money = bcsub((string)$moneyTotal, (string)$diffMoney);
                if ($money < $v->coupon->conditions) {
                    $unavailable[] = $v;
                    continue;
                }
            } elseif ($v->coupon->commodity_limit_type == 3) {
                $allowList = explode(",", $v->coupon->commodity_limit);
                $allowList = array_map(function ($var) {
                    return explode("->", $var);
                }, $allowList);
                $diffCommodity = [];
                foreach ($commodityList as $i => $j) {
                    $explode = explode("->", $j['classify_id']);
                    $flag = self::arrayMatch($explode, $allowList);
                    if (!$flag)
                        $diffCommodity[] = $j;
                }
                $diffMoney = 0;
                foreach ($diffCommodity as $i => $j) {
                    bcadd((string)$diffMoney, bcmul((string)$j['count'], (string)$j['discount']));
                }
                $money = bcsub((string)$moneyTotal, (string)$diffMoney);
                if ($money < $v->coupon->conditions) {
                    $unavailable[] = $v;
                    continue;
                }
            }
            $available[] = $v;
        }

        return [$available, $unavailable];
    }


    private function arrayMatch($explode, $allowList)
    {
        $flag = false;
        foreach ($allowList as $index => $item) {
            $diff = array_diff($item, $explode);
            if (empty($diff)) {
                $flag = true;
                break;
            }
        }
        return $flag;
    }

    private function setOrderState($status, int $order_type = 0)
    {
        $arr = [];
        //        订单状态: 1-待支付 2-待发货 3-已发货 4-已完结 5-已评价   6-删除 7-部分发货 8-已收货 9-部分收货 10-维权中 11-维权完成 12-已关闭
        switch ($status) {
            case 1:
                $arr = ['mstatus', '=', 11];
                break;
            case 2:
                $arr = ['mstatus', 'in', [21, 12]];
                break;
            case 3:
                if ($order_type == 2)
                    $arr = ['mstatus', 'in', [31, 71, 22, 21]];
                else
                    $arr = ['mstatus', 'in', [31, 71, 22]];
                break;
            case 4:
                $arr = ['mstatus', '=', 41, 32];
                break;
            case 5:
                $arr = ['mstatus', '=', 51];
                break;
            case 6:
                $arr = ['mstatus', '=', 61];
                break;
            case 8:
                $arr = ['mstatus', 'in', [81, 32]];
                break;
            case 12:
                $arr = ['mstatus', 'in', [121, 42]];
                break;
        }

        return $arr;
    }

    private function upOrderState(string $oId)
    {
        upOrderState($oId);
    }

    private function return_coupon(int $oId)
    {
        $find = Order::find($oId);
        $user_coupon = UserCoupon::where('unified_order_no', $find['order_no'])->where('mall_id', $this->mid)->find();
        if (empty($user_coupon)) throw new HttpException(HTTP_UNPROCES, "没有找到该优惠券");
        $coupon = Coupon::where('id', $user_coupon['coupon_id'])->where('mall_id', $this->mid)->find();
        $flag = true;
        //1-待支付 2-待发货 3-已发货 4-已完结 5-已评价   6-删除 7-部分发货 8-已收货 9-部分收货 10-维权中 11-维权完成 12-已关闭
        if (!in_array($find->getData('status'), [1, 2, 3, 7, 9])) {
            throw new HttpException(HTTP_UNPROCES, "该订单状态不能取消订单!");
        }
        if (!empty($coupon['limit_indate_begin']) && !empty($coupon['limit_indate_end'])) {
            if (time() < strtotime($coupon['limit_indate_begin']) || time() > strtotime($coupon['limit_indate_end'])) {
                $flag = false;
            }
        }

        if ($coupon['user_limit_type'] == 1) {
            $count = UserCoupon::where('user_id', $find['user_id'])
                ->where('coupon_id', $user_coupon['coupon_id'])
                ->where('mall_id', $this->mid)
                ->count();

            if ($count >= $coupon['user_limit']) {
                $flag = false;
            }
        }

        if ($flag) {
            $user_coupon->unified_order_no = null;
            $user_coupon->status = 0;
            $user_coupon->save();
        }
    }


    public function orderBalancePay(int $id, int $user_id): array
    {
        $order = Order::where('id', $id)
            ->field('id,money,discount,discount_amount')
            ->where('status', 1)
            ->where('mall_id', $this->mid)
            ->with(['orderCommodity' => function (\think\db\Query $sql) {
                $sql->field('id,order_id,money,discount,discount_amount');
            }])
            ->find();
        if (empty($order))
            throw new Exception('未找到相应的待支付订单', HTTP_INVALID);
        $balance = new BalanceSerivce();
        $balance->setMoney($order);
        $balance->setUserCash($user_id);
        $balance->balanceJudge();
        $balance->balanceDeduction($order->id);
        $balance->balanceGeneralAverage($order->orderCommodity->toArray());
        $order->save([
            'status' => 2,
            'discount_balance' => $balance->getMoney()
        ]);
        return [HTTP_SUCCESS, $order];
    }


    public function testing(int $user_address_id, array $commoditys)
    {

        $cids = array_column($commoditys, 'id');
        $cids = array_unique($cids);

        $address = UserAddress::find($user_address_id);

        $fts = Db::name('commodity')
            ->where('a.id', 'in', $cids)
            ->where('a.mall_id', $this->mid)
            ->alias('a')
            ->join('freight_temp f', 'a.ft_id = f.id', 'LEFT')
            ->field('f.no_carry')
            ->select();
        $code_str = "";
        foreach ($fts as $v) {
            $code_str .= $v['no_carry'] . ',';
        }
        $address_arr = explode(',', $address['address']);
        array_pop($address_arr);
        $code_arr = [];
        foreach ($address_arr as $v) {
            $code_arr[] = Area::where('name', $v)->value('area_code');
        }
        $arr = explode(',', $code_str);
        $intersect = array_intersect($code_arr, $arr);//交集
        if (count($intersect) > 0)
            return true;
        else
            return false;
    }


    public function afterSales(array $data)
    {
        $comms = OrderCommodity::where('id', 'IN', $data['ids'])->field('retreat')->select()->toArray();
        if (count(explode(',', $data['ids'])) == 1) {
            return [HTTP_SUCCESS, $comms[0]['retreat']];
        } else {
            $arr = [1, 2, 3];
            foreach ($arr as $k => $v) {
                foreach (array_column($comms, 'retreat') as $vv) {
                    if (!in_array($v, explode(',', $vv))) unset($arr[$k]);
                }
            }
            return [HTTP_SUCCESS, empty($arr) ? null : implode(',', $arr)];
        }
    }


    public function commodity_limit(float $discount_amount, float $total, float $discount, array $arr)
    {
        //$total = $this->total_order_money($money, $data);
        $flag = $this->bear_coupon($arr['id']);
        if (!$flag) {
            $discount_amount = $total - $discount_amount;
            if ($discount_amount == 0) $discount_amount = 1;
            $scale = bcmul((($arr['original_money'] - $arr['discount_amount']) / $discount_amount), $discount, 2);
            $res = bcsub($arr['original_money'] - $arr['discount_amount'], $scale, 2);
        } else
            $res = $arr['original_money'];
        return $res;
    }


    private function bear_coupon(int $id)
    {
        $cids = explode(',', $this->coupon['coupon']['commodity_limit']);
        $flag = false;
        switch ($this->coupon['coupon']['commodity_limit_type']) {
            case 0:
                $flag = false;
                break;
            case 1:
                if (in_array($id, $cids)) $flag = false;
                break;
            case 2:
                if (in_array($id, $cids)) $flag = true;
                break;
            case 3:
                $find = Commodity::find($id);
                if (in_array($find['classify_id'], $cids)) $flag = false;
                break;
        }
        return $flag;
    }


    private function total_order_money(float $money, array $data)
    {
        foreach ($data as $v) {
            $flag = $this->bear_coupon($v['id']);
            if ($flag) $money -= $v['original_money'];
        }
        return $money;
    }

}